/**
 * Это класс виджета поля ввода текста и чилел.
 * Copyright 2012, Alexander Dashkovsky
 * License: http://www.opensource.org/licenses/mit-license.php
 * @lends widget.Text
 */
widget.Text = widget.Control.extend({

    /** @const */
    WIDGET_CLASS : 'wg_text',

    /**
	 * Конструктор класса
	 * @augments widget.Control
	 * @class Класс виджета поля ввода текста и чилел.
	 *
	 * <p><b>CSS класс для DOM элемента - <code>wg_text</code></b></p>
	 * 
	 * <p><b>Параметры объекта конфигурации:</b></p>
	 * {String} <b>id</b> - Идентификатор компонента поля.</br>
	 * {String} <b>cls</b> - Имя класса css (или нескольких классов через пробел)
	 * которые будут добавлены к полю.</br>
	 * {Object} <b>label</b> - Элемент метки поля.
	 * <div class="shift1">{String} <b>label.text</b> - Текст метки</div>
	 * <div class="shift1">{String} <b>label.cls</b> - Имя класса css, которое 
	 * будет применено к тексту метки</div>
	 * <div class="shift1">{String} <b>label.align</b> - Расположение текста метки 
	 * по отношению к полю. Возможные значения:</div>
	 * <div class="shift2">'<b>'left'</b>' - Текст метки прижат к левому краю выделенной области</div>
	 * <div class="shift2">'<b>'top'</b>' - Текст метки сверху над полем</div>
	 * <div class="shift2">'<b>'right'</b>' - Текст метки прижат к правому краю выделенной области</div>
	 * <div class="shift1">Если атрибут label.align не задан, текст метки будет
	 * прижат к левому краю выделенной области (когда label.width задан).</div> 
	 * <div class="shift1">{Int} <b>label.width</b> - Ширина области, отведенной
	 * под текст метки. Если не задано, label и field следуют друг за другом.</div>
	 * {Object} <b>input</b> - Элемент поля ввода.
	 * <div class="shift1">{String} <b>input.type</b> - Тип поля. Не обязательный параметр.
	 * По умолчанию type="text". Если задан type="password", вводимые символы не будут паказываться.</div>
	 * <div class="shift1">{String} <b>input.cls</b> - Имя класса css, которое 
	 * будет применено к тексту поля ввода</div>
	 * <div class="shift1">{String} <b>input.align</b> - Расположение текста в
	 * поле ввода. Возможные значения:</div>
	 * <div class="shift2">'<b>'left'</b>' - Текст прижат к левому краю поля</div>
	 * <div class="shift2">'<b>'center'</b>' - Текст находится по центру поля</div>
	 * <div class="shift2">'<b>'right'</b>' - Текст метки прижат к правому краю поля</div>
	 * <div class="shift1">Если атрибут input.align не задан, текст будет
	 * прижат к левому поля (когда input.width задан).</div> 
	 * <div class="shift1">{Int} <b>input.width</b> - Ширина области поля ввода.</div>
	 * <div class="shift1">{String} <b>input.placeHolder</b> - Текстовая подсказка в области поля ввода (только для HTML5).</div>
	 * {String} <b>value</b> - Значение, которое будет показано при прорисовке компонента.</br>
	 * {ElementDOM} <b>renderTo</b> - Элемент DOM, в который будет прорисована поле.</br>
	 * {Object} <b>listeners</b> - Объект слушателей событий.</br>
	 * 
	 * <p><b>События:</b></p>
	 * <div><b>afterrender</b> - Вызывается сразу после прорисовки поля.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент поля.</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент поля.</div>
	 * <div><b>click</b> - Вызывается при клике на область компонента.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент поля</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент поля</div>
	 * <div><b>change</b> - Вызывается при выборе из списка нового эламента.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>record</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент поля</div>
	 * <div class="shift2"><b>record</b> - запись выбранного элемента из списка.</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент поля.</div>
	 * <div><b>hide</b> - Вызывается когда кнопка была спрятана.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент кнопки</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент кнопки</div>
	 * <div><b>show</b> - Вызывается когда кнопка была показана.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент кнопки</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент кнопки</div>
	 * 
	 * <p><b>Пример:</b></p>
	 * <pre class="code">
	 * <i>// Наименование поля располагается слева. Текст в поле выравнивается по центру.</i>
	 * <i>// Справа от поля есть дополнительная метка "px"</i>
	 * var inp1 = new widget.Text({
	 * 	id : 'inp1',
	 * 	cls : 'inp',
	 * 	label : {
	 * 		text : 'Ширина линии:',
	 * 		cls : 'label',
	 * 		align : 'left',
	 * 		width : 90
	 * 	},
	 * 	input : {
	 * 		align : 'center',
	 * 		cls : 'textBold',
	 * 		width : 20
	 * 	},
	 * 	validate : {
	 * 		onlyNumber : true,
	 * 		maxLength : 2
	 * 	},	
	 * 	labelAfter : {
	 * 		text : 'px',
	 * 		cls : 'labelAfter'
	 * 	},
	 * 	renderTo : $('#controls'),
	 * 	listeners : {
	 * 		change : function(field, value, elementDom){
	 * 			console.log('-- new value = ' + value);
	 * 		}
	 * 	}
	 * });
	 * 
	 * <i>// Наименование поля располагается сверху. Текст в поле выравнивается к левому краю.</i>
	 * var fName = new widget.Text({
	 * 	id : 'fName',
	 * 	name : 'firstName',
	 * 	cls : 'inp',
	 * 	label : {
	 * 		text : 'First Name',
	 * 		cls : 'label',
	 * 		align : 'top'
	 * 	},
	 * 	input : {
	 * 		align : 'left',
	 * 		cls : 'textBold',
	 * 		width : 240
	 * 	},
	 * 	value : 'Вася',
	 * 	renderTo : $('#fields'),
	 * 	listeners : {
	 * 		change : function(field, value, elementDom){
	 * 			console.log('-- First Name = ' + value);
	 * 		}
	 * 	}
	 * });
	 * </pre>
	 * 
	 * @constructs
	 * @param {object} config Конфигурационный объект компонента.
	 */
    constructor : function(config) {
        this.config = config || {};
        this.base(this.config.id, this.WIDGET_CLASS, this.config.label, this.config.value);	         
        if (this.config.renderTo) {
            this.render(this.config.renderTo);
        }
    },
    /**
	 * Выполняется отрисовка поля.
     * @public 
	 * @function
     * @memberOf widget.Text#
	 * @param (elementDOM) renderTo Элемент DOM, внутри которого будет создано поле.
	 * Если этот параметр не задавать, а поле уже ранее прорисовывалось, то оно 
	 * будет перерисоваться в тот же контейнер. Если в контейнере существуют и 
	 * другие виджеты, render() без параметра прорисует этот виджет после всех 
	 * остальных.
	 * @return none
	 */
    render : function(renderTo) {
        var me = this;         
        if (this.element) {
            this.element.remove();
        }

        if (renderTo) {
            this.renderContainer = renderTo;
        } else {
            renderTo = this.renderContainer;
        }
        
        var name = (this.config.name)? this.config.name : "";
		
        var inputTpl = '<td><input';
        if (this.value) {
            inputTpl += ' value="'+this.value+'"';
        }
        else if (this.config.input.placeHolder){
            inputTpl += ' placeholder="' + this.config.input.placeHolder + '"';
        }
        inputTpl += ' class="' + this.WIDGET_CLASS + '_input" name="'+name+'" id="'+this.config.input.id+'"';
        if (this.config.input.type == 'password') {
            inputTpl += ' type="password"';
        } else {
            inputTpl += ' type="text"';
        }
        inputTpl += '/></td>';

        var tpl = '<div class="' + this.WIDGET_CLASS + '" id="' + this.getId() + '">';
        tpl += '<table>';	
        if (this.config.label && this.config.label.text) {
            if (this.config.label.align == 'top') {
                tpl += '<tr><td><label class="labelBefore">' + this.config.label.text + '</label></td></tr>';
                tpl += '<tr>' + inputTpl;	
            }
            else {
                tpl += '<tr><td';
                if (this.config.label.align == 'right') {
                    tpl += ' style="text-align:right !important;"';
                }
                tpl += '><label>' + this.config.label.text + '</label></td>';
                tpl += inputTpl;	
            }
        }
        else {
            tpl += '<tr>' + inputTpl;	
        }
			
        if (this.config.labelAfter && this.config.labelAfter.text) {
            tpl += '<td><label class="labelAfter">' + this.config.labelAfter.text + '</label></td>';
        }
        tpl += '</tr></table>';		
        tpl += '</div>';


        if (this.element) {
            this.element.remove();
        }
		
        this.element = $(tpl);	
        this.inputEl = $(me.element).find('input')[0];

        if (this.config.cls) {
            this.applyClassToElement(this.config.cls, this.element)
        }
        if (this.config.overCls) {
            this.applyOverClassToElement(this.config.overCls, this.element)
        }	
        this.labelEl = $(this.element).find("label");
        if (this.config.label) {
            if (this.config.label.cls) {
                $(this.labelEl).addClass(this.config.label.cls);
            }
            if (this.config.label.width) {
                $(this.labelEl).parent().width(this.config.label.width);
            }
        }
        if (this.config.input) {
            if (this.config.input.cls) {
                $(this.inputEl).addClass(this.config.input.cls);
            }
            if (this.config.input.align) {
                $(this.inputEl).attr('style', 'text-align:'+this.config.input.align+' !important');
            }
            if (this.config.input.width) {
                $(this.inputEl).width(this.config.input.width);
            }
        }

        if (renderTo) {
            $(this.element).appendTo(renderTo);
            if(this.config.autocomplete){
                console.log(this.config.autocomplete);
                $("#"+this.config.id).autocomplete({
                    source:this.config.autocomplete
                });
            }
            $(this.element).click(function(event) {
                me.onClick();
                (window.event) ? event.cancelBubble = true : event.stopPropagation();
            });
					
            $(this.inputEl).keyup(function(event) {	
				
                //Убираем всё кроме чисел если включена валидация OnlyNumber
                if(me.config.validate && me.config.validate.onlyNumber){
                    var str = $(this).val();
					
                    var re = /(\d+(\.\d+)?)*\d+(\.\d+)?(\D|$)/g;
					
                    var value = '';
                    var matches = str.match( re );
                    if(matches)
                    {
                        for(var i=0; i<matches.length; i++) {	
                            var match = matches[i]			  
                            value = value+''+match.replace( /\D$/ , '');				  
                        }															
                    }								
                }
				
                if(me.config.validate && me.config.validate.maxLength){
                    if($(this).val().length>me.config.validate.maxLength){
                        var value = str.substring(0,me.config.validate.maxLength);
                    }
                }
				
                else{
                    var value = $(this).val();
                }
				
                $(this).val(value);						
                return false;					
            });

            $(this.inputEl).change(function() {
                var value = $(this).val();
                me.setValue(value);
                me.onChange();
            });
					
            this.onAfterRender();
        }
    },

    /**
	 * Функция отрабатывает сразу после прорисовки конпонента.
     * @private 
	 * @function
	 */
    onAfterRender : function() {
        if (this.config.listeners && this.config.listeners.afterrender) {
            this.config.listeners.afterrender(this, this.element);
        }
    },

    /**
	 * Функция отрабатывает сразу после клика мышки на компоненте.
     * @private 
	 * @function
	 */
    onClick : function() {
        if (this.config.listeners && this.config.listeners.click) {
            this.config.listeners.click(this, this.element);
        }
    },

    /**
	 * Функция отрабатывает сразу после выбора любого элемента из списка.
     * @private 
	 * @function
	 */
    onChange : function() {
        if (this.config.listeners && this.config.listeners.change) {
            this.config.listeners.change(this, this.getValue(), this.element);
        }
    },

    /**
	 * Спрятать поле
     * @public 
	 * @function
     * @memberOf widget.Text#
	 */
    hide : function() {
        var oldVisible = this.visible;
        this.visible = false;
        if (this.visible != oldVisible) {
            this.element.addClass("hidden");
            this.onHide();
        }
    },

    /**
	 * Показать поле
     * @public 
	 * @function
     * @memberOf widget.Text#
	 */
    show : function() {
        var oldVisible = this.visible;
        this.visible = true;
        if (this.visible != oldVisible) {
            this.element.removeClass("hidden");
            this.onShow();
        }
    },

    /**
	 * Функция отрабатывает после того, как элемент будет спрятан.
     * @private 
	 * @function
	 */
    onHide : function() {
        if (this.config.listeners && this.config.listeners.hide) {
            this.config.listeners.hide(this, this.element);
        }
    },

    /**
	 * Функция отрабатывает после того, как элемент будет показан.
     * @private 
	 * @function
	 */
    onShow : function() {
        if (this.config.listeners && this.config.listeners.show) {
            this.config.listeners.show(this, this.element);
        }
    },

    /**
	 * Возвращает элемент DOM, принадлежащий label
     * @public 
	 * @function
     * @memberOf widget.Text#
	 */
    getLabelEl : function() {
        return this.labelEl;
    },

    /**
	 * Возвращает элемент DOM, принадлежащий field
     * @public 
	 * @function
     * @memberOf widget.Text#
	 */
    getFieldEl : function() {
        return this.fieldEl;
    },
	
    /**
	 * Возвращает элемент DOM, принадлежащий контейнеру компонента
	 * @public 
	 * @function
     * @memberOf widget.Text#
	 */
    getRenderContainer : function() {
        return this.renderContainer;
    }

});

